unit AmbienteGrid;

interface
uses
  Ambiente, Estado, Acao, EstadoGrid, Grids;

type
  TAmbienteGrid = class (TAmbiente)
    private
      FEstados : array of array of TEstadoGrid;

      FTamanhoX,
      FTamanhoY : Integer;

      FEstadoAntigoAgente : TEstado;
    function GetEstados(Ix, Jx: Integer): TEstado;

    public
      constructor Create (TamanhoX, TamanhoY : Integer);

      function NovoEstado (s : TEstado; a: TAcao) : TEstado; override;
      function Recompensa : Double; override;

      property TamanhoX: Integer read FTamanhoX write FTamanhoX;
      property TamanhoY: Integer read FTamanhoY write FTamanhoY;
      property Estados[Ix, Jx : Integer] : TEstado read GetEstados;

      procedure LoadFromStringGrid (StringGrid : TStringGrid);


  end;

implementation
uses
  AcaoGrid, SysUtils, Math;

{ TAmbienteGrid }

constructor TAmbienteGrid.Create(TamanhoX, TamanhoY: Integer);
var
  i, j : Integer;
  s : TEstadoGrid;
begin
  FTamanhoX := TamanhoX;
  FTamanhoY := TamanhoY;

  SetLength(FEstados, TamanhoY, TamanhoX);

  for i := 0 to TamanhoY -1 do
    begin
      for j := 0 to TamanhoX -1 do
        begin
          s := TEstadoGrid.Create(i, j, '');

          FEstados[i, j] := s;
          FEstadoAgente := s;
        end;
    end;
end;

function TAmbienteGrid.GetEstados(Ix, Jx: Integer): TEstado;
begin
  Result := FEstados[Ix, Jx];
end;

procedure TAmbienteGrid.LoadFromStringGrid(StringGrid: TStringGrid);
var
  Ix,
  Jx : Integer;

  s : TEstadoGrid;
begin

  for Ix := 0 to FTamanhoY-1 do
    begin
      for Jx := 0 to FTamanhoX-1 do
        begin
          FreeAndNil(FEstados[Ix, Jx]);
        end;
    end;

  FTamanhoX := StringGrid.ColCount;
  FTamanhoY := StringGrid.RowCount;

  SetLength(FEstados, FTamanhoY, FTamanhoX);

  for Ix := 0 to FTamanhoY-1 do
    begin
      for Jx := 0 to FTamanhoX-1 do
        begin
          s := TEstadoGrid.Create (Jx, Ix, StringGrid.Cells[Jx, Ix]);

          FEstados[Ix, Jx] := s;
          FEstadoAgente := s;
        end;
    end;

  for Ix := 0 to FTamanhoY-1 do
    begin
      for Jx := 0 to FTamanhoX-1 do
        begin
          if (FEstados[Ix, Jx].Propriedade = pgBuraco) then
            begin
              if (Ix > 0) and (FEstados[Ix-1, Jx].Propriedade = pgLimpo) then
                begin
                  s := FEstados[Ix-1, Jx];
                  FreeAndNil(s);

                  s := TEstadoGrid.Create (Jx, Ix-1, '-');
                  FEstados[Ix-1, Jx] := s;
                end;
              if (Jx > 0) and (FEstados[Ix, Jx-1].Propriedade = pgLimpo) then
                begin
                  s := FEstados[Ix, Jx-1];
                  FreeAndNil(s);

                  s := TEstadoGrid.Create (Jx-1, Ix, '-');
                  FEstados[Ix, Jx-1] := s;
                end;
              if (Ix < FTamanhoY-1) and (FEstados[Ix+1, Jx].Propriedade = pgLimpo) then
                begin
                  s := FEstados[Ix+1, Jx];
                  FreeAndNil(s);

                  s := TEstadoGrid.Create (Jx, Ix+1, '-');
                  FEstados[Ix+1, Jx] := s;
                end;
              if (Jx < FTamanhoX-1) and (FEstados[Ix, Jx+1].Propriedade = pgLimpo) then
                begin
                  s := FEstados[Ix, Jx+1];
                  FreeAndNil(s);

                  s := TEstadoGrid.Create (Jx+1, Ix, '-');
                  FEstados[Ix, Jx+1] := s;
                end;

            end;
        end;
    end;
end;


function TAmbienteGrid.NovoEstado(s: TEstado; a: TAcao): TEstado;
var
  sgrid : TEstadoGrid;
  agrid : TAcaoGrid;

  randX, randY : Integer;
begin
  sgrid := TEstadoGrid(s);
  agrid := TAcaoGrid(a);

  Result := s;
  FEstadoAntigoAgente := s;
  case agrid.Tipo of
    tagCima :
      begin
        if (sgrid.Y - 1) >= 0 then
          Result := FEstados[sgrid.Y - 1, sgrid.X];
      end;
    tagDireita :
      begin
        if (sgrid.X + 1) < FTamanhoX then
          Result := FEstados[sgrid.Y, sgrid.X + 1];
      end;
    tagBaixo :
      begin
        if (sgrid.Y + 1) < FTamanhoY then
          Result := FEstados[sgrid.Y + 1, sgrid.X];
      end;
    tagEsquerda :
      begin
        if (sgrid.X - 1) >= 0 then
          Result := FEstados[sgrid.Y, sgrid.X - 1];
      end;
    tagFicar :
      begin
        Result := FEstados[sgrid.Y, sgrid.X];
      end;
  end;

  //caso caia no buraco, transporta o agente para um lugar aleatorio diferente de buraco.
  FEstadoAgente := Result;
  while (TEstadoGrid(FEstadoAgente).Propriedade = pgBuraco) do
    begin
      randX := Random(TamanhoX);
      randY := Random(TamanhoY);

      FEstadoAgente := FEstados[randY, randX];

    end;

end;

function TAmbienteGrid.Recompensa: Double;
var
  sgrid : TEstadoGrid;
begin
  sgrid := TEstadoGrid(FEstadoAgente);

  if sgrid.Propriedade = pgOuro then
    Result := 100
  else if sgrid.Propriedade = pgBuraco then
    Result := -100
  else if sgrid.Propriedade = pgVento then
    Result := 0
  else
    Result := 0;


end;

end.
